home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / pascal / fmat.zip / FMAT.PAS < prev   
Pascal/Delphi Source File  |  1987-01-27  |  16KB  |  489 lines

  1.   {
  2.   Demonstrates formatting a floppy disk from Turbo Pascal.
  3.   This version only formats DSDD 9 sector floppies (360KB).
  4.   Works with DOS 2.0 or 3.0 in either 360K or 1.2M drives.
  5.   Does not support a /S option.
  6.   Supports a /V or -V option that turns on the verify after format.
  7.   With verify off (the default) obtains a 2x speedup vs. DOS format.
  8.  
  9.   Requires Turbo version 3.0 to compile. Compile with Minheap=Maxheap=$200.
  10.   Requires a cloning procedure after being compiled to a .COM file.
  11.   The cloning procedure copies the boot sector of an already-formatted
  12.   floppy into the program, where it can be used thereafter. To clone,
  13.   call the program as follows:
  14.  
  15.   FMAT @ <enter>
  16.  
  17.   Written 10/26/85. Kim Kokkonen, TurboPower Software.
  18.   Compuserve 72457,2131. (408)-378-3672.
  19.   Modified at Hyperion Records 01/27/87, by R.G.Howard
  20.   }
  21.  
  22. PROGRAM fmat;
  23.     {-format a disk, DSDD 9 sectors per track only}
  24.   TYPE
  25.     {holds sector data during sector setup after formatting}
  26.     SectorBuffer = ARRAY[1..512] OF Char;
  27.     {same size as sector buffer but easily initialized in code segment}
  28.     FakeSectorBuffer = RECORD
  29.                          l, h : STRING[255];
  30.                        END;
  31.     FormatRecord = RECORD
  32.                      cyl, hed, rec, num : Byte;
  33.                    END;
  34.     FormatArray = ARRAY[1..18] OF FormatRecord;
  35.     DiskBaseRec = RECORD
  36.                     unk1, unk2, mtr, bps, eot, gpl,
  37.                     dtl, glf, fbf, hst, mst : Byte;
  38.                   END;
  39.     DiskBasePtr = ^DiskBaseRec;
  40.     registers = RECORD
  41.                   CASE Integer OF
  42.                     1 : (ax, bx, cx, dx, bp, si, di, ds, es, flags : Integer);
  43.                     2 : (al, ah, bl, bh, cl, ch, dl, dh : Byte);
  44.                 END;
  45.     FATtable = ARRAY[0..1023] OF Byte;
  46.  
  47.   CONST
  48.     {bootrecord is customized after the .COM file is created.
  49.     call FMAT with a single command line parameter '@' as follows:
  50.     FMAT @ <Enter>. This will fill in bootrecord with a real boot record}
  51.     BootRecord : FakeSectorBuffer = {fill in with bootrecord}
  52.     (l : ''; h : '');
  53.  
  54.   VAR
  55.     reg : registers;
  56.     SB : SectorBuffer;        {will fill in with dir sectors}
  57.     BR : SectorBuffer ABSOLUTE BootRecord;
  58.     VB : ARRAY[1..9] OF SectorBuffer; {will use for fast verify}
  59.     FMT : FormatArray;
  60.     FAT : FATtable;
  61.     drName : STRING[2];
  62.     param : STRING[10];
  63.     drive, dType : Byte;
  64.     ch : Char;
  65.     doVerify : Boolean;
  66.     BiosDiskBase : DiskBasePtr ABSOLUTE 0 : $78;
  67.     OldDiskBase : DiskBasePtr;
  68.     i, error : Integer;
  69.     tavail : Integer;
  70.     bavail : Real;
  71.  
  72.   PROCEDURE BIOSreadSectors(funct, drive : Byte;
  73.                             sector, track, head : Integer;
  74.                             sects : Integer;
  75.                             VAR buffer;
  76.                             VAR error : Integer);
  77.       {-execute int 13 to read disk or verify via BIOS at low level}
  78.     BEGIN
  79.       reg.ax := (funct SHL 8) OR sects;
  80.       reg.dl := drive;
  81.       reg.dh := head;
  82.       reg.ch := track AND 255;
  83.       reg.cl := (sector AND 63) OR ((track SHR 8) SHL 6);
  84.       reg.es := Seg(buffer);
  85.       reg.bx := Ofs(buffer);
  86.       Intr($13, reg);
  87.       IF Odd(reg.flags AND 1) THEN
  88.         error := reg.ax SHR 8
  89.       ELSE
  90.         error := 0;
  91.     END {biosreadsectors} ;
  92.  
  93.   PROCEDURE BIOSwriteSectors(drive : Byte;
  94.                              sector, track, head : Integer;
  95.                              sects : Integer;
  96.                              VAR buffer : SectorBuffer;
  97.                              VAR error : Integer);
  98.       {-execute int 13 to write disk via BIOS at low level}
  99.     BEGIN
  100.       reg.ax := $300 OR sects;
  101.       reg.dl := drive;
  102.       reg.dh := head;
  103.       reg.ch := track AND 255;
  104.       reg.cl := (sector AND 63) OR ((track SHR 8) SHL 6);
  105.       reg.es := Seg(buffer);
  106.       reg.bx := Ofs(buffer);
  107.       Intr($13, reg);
  108.       IF Odd(reg.flags AND 1) THEN BEGIN
  109.         error := reg.ax SHR 8;
  110.         WriteLn('error during format...');
  111.         Halt;
  112.       END ELSE
  113.         error := 0;
  114.     END {bioswritesectors} ;
  115.  
  116.   PROCEDURE InitBoot;
  117.       {-self-customize this program to hold the boot record}
  118.     VAR
  119.       ch : Char;
  120.       error : Integer;
  121.       f : FILE;
  122.       tries : Byte;
  123.  
  124.     FUNCTION CodeSize : Integer;
  125.         {thanks to Bob Tolz and Randy Forgaard for this function}
  126.       VAR
  127.         i : Byte;
  128.       BEGIN
  129.         i := 11;
  130.         WHILE NOT((Mem[DSeg-2 : i+3] <> $00E9) AND (MemW[DSeg-2 : i+4] = $0000)) AND
  131.         NOT((MemW[DSeg-2 : i+0] = $00E9) AND (MemW[DSeg-2 : i+2] = $E800)) DO
  132.           i := i+1;
  133.         CodeSize := ((((DSeg-2)-CSeg) SHL 4)+i+6)-$100
  134.       END {CodeSize} ;
  135.  
  136.     BEGIN
  137.       WriteLn('You will now clone a copy of the boot record into this program...');
  138.       WriteLn('The completed version will be written to FMAT.COM');
  139.       Write('Place a DOS formatted disk in drive A: and press any key when ready ');
  140.       Read(Kbd, ch);
  141.       WriteLn;
  142.       {read the boot record}
  143.       tries := 0;
  144.       REPEAT
  145.         tries := Succ(tries);
  146.         BIOSreadSectors(2, 0, 1, 0, 0, 1, BR, error);
  147.       UNTIL (error = 0) OR (tries = 3);
  148.       IF error <> 0 THEN BEGIN
  149.         WriteLn('could not read boot record');
  150.         Halt;
  151.       END;
  152.       {clone this program}
  153.       Assign(f, 'FMAT.COM');
  154.       Rewrite(f, 1);
  155.       BlockWrite(f, Mem[CSeg : $100], CodeSize);
  156.       Close(f);
  157.       Halt;
  158.     END {initboot} ;
  159.  
  160.   FUNCTION DOSversion : Byte;
  161.       {-return the major version number of DOS}
  162.     BEGIN
  163.       reg.ah := $30;
  164.       MsDos(reg);
  165.       DOSversion := reg.al;
  166.     END {dosversion} ;
  167.  
  168.   FUNCTION ATmachine : Boolean;
  169.       {-return true if machine is AT class}
  170.     VAR
  171.       machtype : Byte ABSOLUTE $FFFF : $000E;
  172.     BEGIN
  173.       ATmachine := (machtype = $FC);
  174.     END {ATmachine} ;
  175.  
  176.   PROCEDURE readDASD(drive : Byte; VAR dType : Byte);
  177.       {-read dasd for DOS 3}
  178.       {-whatever dasd is!}
  179.     BEGIN
  180.       reg.ah := $15;
  181.       reg.dl := drive;
  182.       Intr($13, reg);
  183.       IF Odd(reg.flags AND 1) THEN BEGIN
  184.         WriteLn('error reading DASD for format...');
  185.         Halt;
  186.       END;
  187.       dType := reg.ah;
  188.     END {readdasd} ;
  189.  
  190.   PROCEDURE setDASD(drive, dType : Byte);
  191.       {-execute int 13 to "set DASD" for format of 360K disks on 1.2MB floppies}
  192.     VAR
  193.       tries : Byte;
  194.     BEGIN
  195.       tries := 0;
  196.       REPEAT
  197.         tries := Succ(tries);
  198.         reg.ah := $17;
  199.         reg.al := dType;
  200.         reg.dl := drive;
  201.         Intr($13, reg);
  202.       UNTIL (tries = 3) OR NOT(Odd(reg.flags AND 1));
  203.  
  204.       IF Odd(reg.flags AND 1) THEN BEGIN
  205.         WriteLn('error setting DASD for format...');
  206.         Halt;
  207.       END;
  208.     END {setdasd} ;
  209.  
  210.   PROCEDURE InitFAT;
  211.       {-initialize a FAT sector}
  212.     BEGIN
  213.       {fill fat with all zeros}
  214.       FillChar(FAT, 1024, 0);
  215.       {fill in the ID Bytes}
  216.       FAT[0] := $FD;          {9 sector DSDD drive}
  217.       FAT[1] := $FF;          {boilerplate}
  218.       FAT[2] := $FF;
  219.       tavail := 80;
  220.     END {initfat} ;
  221.  
  222.   PROCEDURE InitDiskBase;
  223.       {-modify the disk base data per DOS 3 instructions}
  224.     BEGIN
  225.       {save old pointer}
  226.       OldDiskBase := BiosDiskBase;
  227.       {make a new disk base data area}
  228.       New(BiosDiskBase);
  229.       {put the data from the old area in the new one}
  230.       BiosDiskBase^ := OldDiskBase^;
  231.       {modify per dos 3 instructions, doesn't hurt on DOS 2}
  232.       BiosDiskBase^.glf := $50;
  233.       BiosDiskBase^.eot := 9;
  234.     END {initdiskbase} ;
  235.  
  236.   PROCEDURE Format(drive : Byte; VAR FMT : FormatArray; VAR error : Integer);
  237.       {-lay down format tracks}
  238.     VAR
  239.       i : Integer;
  240.     BEGIN
  241.       {initialize format table}
  242.       FOR i := 1 TO 9 DO
  243.         WITH FMT[i] DO BEGIN
  244.           cyl := 0;           {cylinder number, will fill in during format}
  245.           hed := 0;           {head number}
  246.           rec := i;           {sector number}
  247.           num := 2;           {indicates 512 bytes per sector}
  248.         END;
  249.       FOR i := 1 TO 9 DO
  250.         WITH FMT[i+9] DO BEGIN
  251.           cyl := 0;           {cylinder number, will fill in during format}
  252.           hed := 1;           {head number}
  253.           rec := i;           {sector number}
  254.           num := 2;           {indicates 512 bytes per sector}
  255.         END;
  256.       {write the format information}
  257.       INLINE(
  258.         $8A/$56/$0C/          {MOV    DL,[BP+0C] - get drive number}
  259.         $C4/$5E/$08/          {LES    BX,[BP+08] - get pointer to format array}
  260.         $B9/$01/$00/          {MOV    CX,0001 - track 0 sector 1}
  261.  
  262.         {nexttrack: - loop over 40 disk tracks}
  263.         $8B/$FB/              {MOV    DI,BX - index into format array}
  264.         $B0/$12/              {MOV    AL,12 - number of sectors per track = 18}
  265.  
  266.         {inittrack: - loop over 18 sectors per track}
  267.         $26/$88/$2D/          {MOV    ES:[DI],CH - track track number in format array}
  268.         $81/$C7/$04/$00/      {ADD    DI,0004}
  269.         $FE/$C8/              {DEC    AL}
  270.         $75/$F5/              {JNZ    inittrack}
  271.  
  272.         $B6/$00/              {MOV    DH,00 - format 9 sectors on side 0}
  273.         $B8/$01/$05/          {MOV    AX,0501}
  274.         $CD/$13/              {INT    13}
  275.         $72/$18/              {JB     error - check for errors}
  276.  
  277.         $B6/$01/              {MOV    DH,01 - format 9 sectors on side 1}
  278.         $B8/$01/$05/          {MOV    AX,0501}
  279.         $53/                  {PUSH    BX}
  280.         $81/$C3/$24/$00/      {ADD    BX,0024}
  281.         $CD/$13/              {INT    13}
  282.         $72/$0A/              {JB     error - check for errors}
  283.  
  284.         $5B/                  {POP    BX}
  285.         $FE/$C5/              {INC    CH - next track}
  286.         $80/$FD/$28/          {CMP    CH,28}
  287.         $75/$D2/              {JNZ    nexttrack}
  288.  
  289.         $31/$C0/              {XOR    AX,AX - no errors, return 0}
  290.  
  291.         {error:}
  292.         $C4/$7E/$04/          {LES    DI,[BP+04]}
  293.         $26/$89/$05           {MOV    ES:[DI],AX - return error code}
  294.         );
  295.     END {format} ;
  296.  
  297.   PROCEDURE Verify(drive : Byte; VAR FAT : FATtable; VAR error : Integer);
  298.       {-verify that sectors were formatted}
  299.     VAR
  300.       t, h : Integer;
  301.       cluster, fatofs, topcluster, content : Integer;
  302.     BEGIN
  303.       {initialize the verify buffer - 9 sectors * 512 bytes}
  304.       FillChar(VB, 4608, $F6);
  305.       {verify all sectors}
  306.       FOR t := 0 TO 39 DO
  307.         FOR h := 0 TO 1 DO BEGIN
  308.           BIOSreadSectors(4, drive, 1, t, h, 9, VB, error);
  309.  
  310.           IF error <> 0 THEN BEGIN
  311.             {mark the clusters on this track as unavailable}
  312.             cluster := ((9*(h+2*t)) DIV 2)-4;
  313.             topcluster := cluster+5;
  314.             WHILE cluster < topcluster DO BEGIN
  315.               fatofs := (3*cluster) DIV 2;
  316.               {get a word from the FAT}
  317.               Move(FAT[fatofs], content, 2);
  318.               {replace 12 bits of the word}
  319.               IF Odd(cluster) THEN
  320.                 content := content OR $FF70
  321.               ELSE
  322.                 content := content OR $0FF7;
  323.               {store it back}
  324.               Move(content, FAT[fatofs], 2);
  325.               cluster := Succ(cluster);
  326.             END;
  327.  
  328.             {reduce the number of tracks available}
  329.             tavail := Pred(tavail);
  330.           END;
  331.         END;
  332.     END {verify} ;
  333.  
  334.   PROCEDURE InitDIR;
  335.       {-initialize a sector for the root directory}
  336.     VAR
  337.       i : Integer;
  338.     BEGIN
  339.       {fill with format bytes}
  340.       FillChar(SB, 512, $F6);
  341.       {mark each directory entry as available}
  342.       FOR i := 1 TO 481 DO
  343.         IF ((i-1) MOD 32) = 0 THEN SB[i] := #0;
  344.     END {initdir} ;
  345.  
  346.   BEGIN
  347.  
  348.     doVerify := False;
  349.  
  350.     {get the drive and doverify option}
  351.     IF ParamCount = 0 THEN BEGIN
  352.       Write('Enter drive to format: ');
  353.       ReadLn(drName);
  354.     END ELSE BEGIN
  355.       {read the command line parameters}
  356.       i := 1;
  357.       drName := '';
  358.       WHILE i <= ParamCount DO BEGIN
  359.         param := ParamStr(i);
  360.         CASE param[1] OF
  361.           '@' : InitBoot;     {clone the boot record into this program}
  362.           '-', '/' :          {check for options}
  363.             IF (Length(param) = 2) AND (UpCase(param[2]) = 'V') THEN
  364.               doVerify := True
  365.             ELSE
  366.               WriteLn('WARNING: unrecognized command line option ', param);
  367.         ELSE
  368.           drName := param;
  369.         END;
  370.         i := Succ(i);
  371.       END;
  372.     END;
  373.  
  374.     {make sure the bootrecord has been cloned into program}
  375.     IF BR[1] = #0 THEN BEGIN
  376.       WriteLn('You must first clone a copy of the boot record');
  377.       WriteLn('into this program. Call as FMAT @ <Enter> to clone...');
  378.       Halt;
  379.     END;
  380.  
  381.     {check for errors, should use DOS facilities to check non-removables}
  382.     IF (drName = '') OR NOT(UpCase(drName[1]) IN ['A', 'B']) THEN BEGIN
  383.       WriteLn('Drive not Specified or cannot be formatted');
  384.       Halt;
  385.     END;
  386.  
  387.     {REPEAT} {This until is found in last line before END.}
  388.  
  389.       {get BIOS drive number}
  390.       drive := Ord(UpCase(drName[1]))-65;
  391.  
  392.       {Write('Insert new disk in drive ', Chr(65+drive));
  393.       Write(' and press <Enter> to begin formatting ');
  394.       REPEAT
  395.         Read(Kbd, ch)
  396.       UNTIL (ch = ^M);}
  397.       WriteLn;
  398.  
  399.       IF ATmachine AND (DOSversion = 3) THEN BEGIN
  400.  
  401.         {get the drive type, necessary when dealing with 1.2MB drives}
  402.         readDASD(drive, dType);
  403.         IF (dType = 0) OR (dType = 3) THEN BEGIN
  404.           WriteLn('Drive is not present or non-removable');
  405.           Halt;
  406.         END;
  407.         IF dType = 2 THEN
  408.           WriteLn('Formatting 360K floppy in 1.2MB drive');
  409.  
  410.         {set the DASD type accordingly}
  411.         setDASD(drive, dType);
  412.  
  413.       END;
  414.  
  415.       Write('Formatting... ');
  416.  
  417.       {set up the disk_base table}
  418.       InitDiskBase;
  419.  
  420.       {lay down format tracks}
  421.       Format(drive, FMT, error);
  422.  
  423.       {restore the disk_base table}
  424.       BiosDiskBase := OldDiskBase;
  425.  
  426.       IF error <> 0 THEN BEGIN
  427.         WriteLn('Error during format...'#7);
  428.         Halt;
  429.       END;
  430.  
  431.       {initialize the FATtable}
  432.       InitFAT;
  433.  
  434.       IF doVerify THEN BEGIN
  435.         {verify sectors}
  436.         Write('Verifying... ');
  437.         Verify(drive, FAT, error);
  438.       END;
  439.  
  440.       IF error <> 0 THEN
  441.         WriteLn('Bad disk, format not verified...'#7)
  442.  
  443.       ELSE BEGIN
  444.  
  445.         Write('Writing BOOT/FAT/DIR... ');
  446.  
  447.         {write the boot record}
  448.         BIOSwriteSectors(drive, 1, 0, 0, 1, BR, error);
  449.  
  450.         {write the FAT sectors}
  451.         Move(FAT[0], SB, 512);
  452.         BIOSwriteSectors(drive, 2, 0, 0, 1, SB, error);
  453.         Move(FAT[512], SB, 512);
  454.         BIOSwriteSectors(drive, 3, 0, 0, 1, SB, error);
  455.         Move(FAT[0], SB, 512);
  456.         BIOSwriteSectors(drive, 4, 0, 0, 1, SB, error);
  457.         Move(FAT[512], SB, 512);
  458.         BIOSwriteSectors(drive, 5, 0, 0, 1, SB, error);
  459.  
  460.         {write the root directory}
  461.         InitDIR;
  462.         BIOSwriteSectors(drive, 6, 0, 0, 1, SB, error);
  463.         BIOSwriteSectors(drive, 7, 0, 0, 1, SB, error);
  464.         BIOSwriteSectors(drive, 8, 0, 0, 1, SB, error);
  465.         BIOSwriteSectors(drive, 9, 0, 0, 1, SB, error);
  466.         BIOSwriteSectors(drive, 1, 0, 1, 1, SB, error);
  467.         BIOSwriteSectors(drive, 2, 0, 1, 1, SB, error);
  468.         BIOSwriteSectors(drive, 3, 0, 1, 1, SB, error);
  469.  
  470.         {calculate bytes available on disk}
  471.         {12 sectors are used by BOOT/FAT/DIR}
  472.         bavail := 512.0*(9.0*tavail-12.0);
  473.         WriteLn('Format complete');
  474.         WriteLn('Bytes Available: ', bavail : 0 : 0);
  475.  
  476.       END;
  477.  
  478.       WriteLn;
  479.       {Write('Format another? (Y/N) ');
  480.       REPEAT
  481.         Read(Kbd, ch);
  482.         ch := UpCase(ch);
  483.       UNTIL (ch IN ['Y', 'N']);
  484.       WriteLn(ch);}
  485.  
  486.     {UNTIL ch = 'N';}
  487.  
  488.   END.
  489.